<#
.SYNOPSIS
A PowerShell script to manage a development Docker container's lifecycle.

.DESCRIPTION
This script provides a simple command-line interface to build, start, stop, and remove
a development container defined by a local Dockerfile and configured via 'config.txt'.
It automates container naming, volume mounting, and attaching a shell.

.PARAMETER Command
(Required) The action to perform. Must be one of 'build', 'start', 'stop', or 'remove'.

.EXAMPLE
PS C:\D\win_docker> .\psDocker.ps1 -Command build
Builds the Docker image using the local Dockerfile and config.txt.

.EXAMPLE
PS C:\D\win_docker> .\psDocker.ps1 -Command start
Starts the development container and attaches an interactive shell.

.EXAMPLE
PS C:\D\win_docker> .\psDocker.ps1 -Command stop
Stops the running development container.

.EXAMPLE
PS C:\D\win_docker> .\psDocker.ps1 -Command remove
Stops and removes the development container.
#>
[CmdletBinding()]
param (
    [Parameter(Mandatory = $true, Position = 0)]
    [ValidateSet('build', 'start', 'stop', 'remove', 'help')]
    [string]$Command
)

# --- Script Setup ---
$ErrorActionPreference = 'Stop'
$ScriptDir = $PSScriptRoot
# FolderName should be the current working directory (where the command is run), not the script location
$FolderName = Split-Path -Leaf (Get-Location -ErrorAction Stop).Path

# --- Configuration Loading ---
Write-Host "INFO: Loading configuration from '$ScriptDir\config.txt'..."
$Config = @{}
try {
    Get-Content "$ScriptDir\config.txt" | ForEach-Object {
        if ($_ -match '^\s*([^#\s=]+)\s*=\s*(.*)\s*$') {
            $key = $Matches[1].Trim()
            $value = $Matches[2].Trim()
            # Strip quotes
            if (($value.StartsWith('"') -and $value.EndsWith('"')) -or ($value.StartsWith("'") -and $value.EndsWith("'"))) {
                $value = $value.Substring(1, $value.Length - 2)
            }
            $Config[$key] = $value
        }
    }
}
catch {
    Write-Error "FATAL: Could not read '$ScriptDir\config.txt'. Please ensure the file exists and is readable."
    exit 1
}

$ImageName = $Config['ImageName']
$ImageVersion = $Config['ImageVersion']

if (-not $ImageName -or -not $ImageVersion) {
    Write-Error "FATAL: 'ImageName' and/or 'ImageVersion' not found in config.txt."
    exit 1
}

# --- Variable Definitions ---
$FullImageTag = "${ImageName}:${ImageVersion}"
# Generate a container name that is unique per user and project folder to avoid collisions.
$ContainerName = "${ImageName}_${ImageVersion}_${env:USERNAME}_${FolderName}"

Write-Host "INFO: Image Name: $ImageName"
Write-Host "INFO: Image Version: $ImageVersion"
Write-Host "INFO: Full Image Tag: $FullImageTag"
Write-Host "INFO: Container Name: $ContainerName"
Write-Host ""

function Convert-WindowsPathToDocker {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    $expanded = [Environment]::ExpandEnvironmentVariables($Path)
    try {
        $resolved = Resolve-Path -Path $expanded -ErrorAction Stop
        $expanded = $resolved.ProviderPath
    }
    catch {
        # Keep best-effort path when the target does not exist yet.
    }

    # Normalize backslashes to forward slashes and preserve drive letter with colon (e.g. C:/path),
    # which Docker on Windows accepts for host path mounts.
    return $expanded -replace '\\', '/'
}

function Get-ContainerIdExact {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [switch]$RunningOnly
    )

    $args = @('ps')
    if (-not $RunningOnly) {
        $args += '-a'
    }
    $args += @('--filter', "name=$Name", '--format', '{{.ID}}|{{.Names}}')

    $lines = docker @args
    foreach ($line in $lines) {
        if ([string]::IsNullOrWhiteSpace($line)) { continue }
        $parts = $line -split '\|', 2
        if ($parts.Count -ge 2 -and $parts[1].Trim() -eq $Name) {
            return $parts[0].Trim()
        }
    }

    return $null
}

# --- Command Dispatch ---
switch ($Command) {
    'build' {
        Write-Host "INFO: Checking for existing image '$FullImageTag'..."
        $image = docker image inspect $FullImageTag -f '{{.Id}}' 2>$null
        if ($image) {
            Write-Host "INFO: Image '$FullImageTag' already exists. Skipping build."
            return
        }

        Write-Host "INFO: Image not found. Starting build..."
        
        # UID/GID detection
        $HostUID = 1000
        $HostGID = 1000

        $BuildCommand = "docker build --build-arg HOST_UID=$HostUID --build-arg HOST_GID=$HostGID -t $FullImageTag -f ""$ScriptDir\Dockerfile"" ""$ScriptDir"""
        Write-Host "INFO: Running build command: $BuildCommand"
        Invoke-Expression $BuildCommand
        
        Write-Host "INFO: Build completed."
    }
    'start' {
        # Check if image exists
        $image = docker image inspect $FullImageTag -f '{{.Id}}' 2>$null
        if (-not $image) {
            Write-Error "FATAL: Image '$FullImageTag' not found. Please run the 'build' command first."
            exit 1
        }

        # Check container status
        $containerId = docker ps -a --filter "name=$ContainerName" --format "{{.ID}}"
        $containerStatus = if ($containerId) { docker inspect $containerId -f '{{.State.Status}}' } else { $null }

        if (-not $containerStatus) {
            Write-Host "INFO: Container '$ContainerName' not found. Creating it now..."

            # Define volume mount: use current working directory (where the command is run), not the script's directory
            $workMount = Convert-WindowsPathToDocker (Get-Location -ErrorAction Stop).Path

            $CreateCommand = "docker run -d --name ""$ContainerName"" -v ""${workMount}:/home/shawn/work"" $FullImageTag"
            Write-Host "INFO: Running command: $CreateCommand"
            Invoke-Expression $CreateCommand
            Write-Host "INFO: Container created and started."
        }
        elseif ($containerStatus -eq 'exited') {
            Write-Host "INFO: Container '$ContainerName' is stopped. Starting it..."
            docker start $ContainerName | Out-Null
        }
        else {
            Write-Host "INFO: Container '$ContainerName' is already running."
        }

        # Attach to the container
        Write-Host "INFO: Attaching to container '$ContainerName'..."
        # This ensures the current terminal's input/output are properly connected to the container's shell.
        $execArgs = @('exec', '--interactive', '--tty', $ContainerName, '/bin/bash')
        Write-Host "INFO: Running command: docker $($execArgs -join ' ')"

        $dockerExecutable = (Get-Command 'docker.exe' -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1)?.Source
        if (-not $dockerExecutable) {
            $dockerExecutable = (Get-Command 'docker' -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
        }

        # Use Start-Process so docker.exe owns the console and stays interactive.
        $process = Start-Process -FilePath $dockerExecutable -ArgumentList $execArgs -NoNewWindow -Wait -PassThru
        if ($process.ExitCode -ne 0) {
            throw "docker exec exited with code $($process.ExitCode)."
        }
        Write-Host "INFO: Detached from container."
    }
    'stop' {
        $containerId = docker ps -a --filter "name=$ContainerName" --format "{{.ID}}"
        if (-not $containerId) {
            Write-Host "INFO: Container '$ContainerName' does not exist. Nothing to do."
            return
        }

        $containerStatus = docker inspect $containerId -f '{{.State.Status}}'
        if ($containerStatus -eq 'running') {
            Write-Host "INFO: Stopping container '$ContainerName'..."
            docker stop $ContainerName | Out-Null
            Write-Host "INFO: Container stopped."
        }
        else {
            Write-Host "INFO: Container '$ContainerName' is not running."
        }
    }
    'remove' {
        $containerId = docker ps -a --filter "name=$ContainerName" --format "{{.ID}}"
        if (-not $containerId) {
            Write-Host "INFO: Container '$ContainerName' does not exist. Nothing to do."
            return
        }

        $containerStatus = docker inspect $containerId -f '{{.State.Status}}'
        if ($containerStatus -eq 'running') {
            Write-Host "INFO: Container is running. Stopping it first..."
            docker stop $ContainerName | Out-Null
            Write-Host "INFO: Container stopped."
        }

        Write-Host "INFO: Removing container '$ContainerName'..."
        docker rm $ContainerName | Out-Null
        Write-Host "INFO: Container removed."
    }
    'help' {
        Get-Help $MyInvocation.MyCommand.Path -Full
    }
}
